home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / BG_SRC.ZIP / BG_MOVE.C < prev    next >
C/C++ Source or Header  |  1992-05-30  |  20KB  |  615 lines

  1. /*
  2.  *
  3.  * B  G  _  M  O  V  E  .  C  , moving and placing the pieces
  4.  * O.F.Ransen:    21st June  1991
  5.  * This version:  30th May   1992
  6.  *
  7.  */
  8.  
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <conio.h>
  12. #include <string.h>
  13. #include "bg.h"
  14.  
  15. /***************************************************************************/
  16.  
  17. char Globerr[GERR_LEN] = "" ;
  18.  
  19. const Layout_t Initial_Layout = {0,               /* the bar */
  20.                                  2,0,0,0,0,0,     /* two runners */
  21.                                  0,0,0,0,0,5,
  22.                                  0,0,0,0,3,0,
  23.                                  5,0,0,0,0,0,     /* home */
  24.                                  0} ;
  25.  
  26. void Initial_Board (Layout_t Layouts[2])
  27. /*
  28. PURPOSE: To initial the layouts to the start of a game.
  29. */
  30. {
  31.     short p ;
  32.     for (p = 0 ; p < N_PLACES ; p++) {
  33.         Layouts [BLACK_PLAYER][p] = Initial_Layout [p] ;
  34.         Layouts [WHITE_PLAYER][p] = Initial_Layout [p] ;
  35.     }
  36. }
  37.  
  38. /*************************************************************************/
  39.  
  40. void Select_Best_Move (Dice_t*    The_Dice,
  41.                        Layout_t   My_Old,     Layout_t   His_Old,
  42.                        Transit_t* My_Best_Tr, Transit_t* His_Best_Tr,
  43.                        Player_t   Player,     Search_t   Search)
  44. /*
  45. PURPOSE: Given the current situation and the two Dice I return
  46.          with the best move possible contained in the
  47.          new layouts.
  48. NOTES:   1) The Transit_t returned show us the new Layouts and how
  49.          we got there.
  50.          2) If the search type is Max_Only then we are just searching
  51.          for the largest number of moves possible, and when we find it
  52.          we can stop searching.
  53. */
  54. {
  55.     Transit_t My_Old_Tr,His_Old_Tr ;
  56.  
  57.     (void)strcpy (Globerr,"Select_Best_Move 1") ;
  58.  
  59.     Init_Transit (My_Best_Tr,My_Old) ;
  60.     Init_Transit (His_Best_Tr,His_Old) ;
  61.  
  62.     Copy_Transit (&My_Old_Tr,My_Best_Tr) ;
  63.     Copy_Transit (&His_Old_Tr,His_Best_Tr) ;
  64.  
  65.     if (The_Dice->N_Vals == 4) {
  66.         /* No problems with order of moves, all 4 the same */
  67.         Lay_Sel_t Best_Score ;
  68.  
  69.         Best_Score.Goodness   = WORST_SCORE ;
  70.         Best_Score.Moves_Made = WORST_SCORE ;
  71.         Select_Best_Ndice_Move (The_Dice,3,
  72.                                 &My_Old_Tr,&His_Old_Tr,
  73.                                 My_Best_Tr,His_Best_Tr,
  74.                                 &Best_Score,Player,Search) ;
  75.  
  76.     } else if (The_Dice->N_Vals == 2) {
  77.         /* Problems with order */
  78.         Select_Best_2Dice_Move (The_Dice,
  79.                                 &My_Old_Tr,&His_Old_Tr,
  80.                                 My_Best_Tr,His_Best_Tr,Player) ;
  81.     } else {
  82.         Error_Exit ("The_Dice->N_Vals very strange...") ;
  83.     }
  84.  
  85.     Check_Layout (My_Best_Tr->Layout, "Checking Mine_New") ;
  86.     Check_Layout (His_Best_Tr->Layout,"Checking His_New") ;
  87.     (void)strcpy (Globerr,"Select_Best_Move 2") ;
  88. }
  89.  
  90. /*************************************************************************/
  91.  
  92. void Select_Best_2Dice_Move (Dice_t*    The_Dice,
  93.                              Transit_t* My_Old_Tr,  Transit_t* His_Old_Tr,
  94.                              Transit_t* My_Best_Tr, Transit_t* His_Best_Tr,
  95.                              Player_t   Player)
  96. /*
  97. PURPOSE: To select the best move trying first Dice_AB and then Dice_BA
  98.          sequence.
  99. NOTES:   1) If we see we are at the opening move of the game then we
  100.          do one of the standard moves contained in BG_STDOP.C
  101. */
  102. {
  103.     Transit_t My_AB,My_BA,His_AB,His_BA ;
  104.     Lay_Sel_t Best_Score_AB,Best_Score_BA ;
  105.     boolean   Copy_AB,Copy_BA ;
  106.     char      Temp ;
  107.  
  108.     (void)strcpy (Globerr,"Select_Best_2Dice_Move 1") ;
  109.  
  110.     if (Standard_Opening (The_Dice,
  111.                           My_Old_Tr,  His_Old_Tr,
  112.                           My_Best_Tr, His_Best_Tr)) {
  113.         return ;
  114.     }
  115.  
  116.     Copy_Transit (&My_AB,My_Old_Tr) ;
  117.     Copy_Transit (&My_BA,My_Old_Tr) ;
  118.     Copy_Transit (&His_AB,His_Old_Tr) ;
  119.     Copy_Transit (&His_BA,His_Old_Tr) ;
  120.  
  121.     Best_Score_AB.Goodness   = WORST_SCORE ;
  122.     Best_Score_AB.Moves_Made = WORST_SCORE ;
  123.     Select_Best_Ndice_Move (The_Dice,1,
  124.                             My_Old_Tr,His_Old_Tr,
  125.                             &My_AB,&His_AB,
  126.                             &Best_Score_AB,Player,Bestest) ;
  127.  
  128.     (void)strcpy (Globerr,"Select_Best_2Dice_Move 2") ;
  129.  
  130.     /* Swap dice order... */
  131.     Temp                = The_Dice->Values[0] ;
  132.     The_Dice->Values[0] = The_Dice->Values[1] ;
  133.     The_Dice->Values[1] = Temp ;
  134.  
  135.     Best_Score_BA.Goodness   = WORST_SCORE ;
  136.     Best_Score_BA.Moves_Made = WORST_SCORE ;
  137.     Select_Best_Ndice_Move (The_Dice,1,
  138.                             My_Old_Tr,His_Old_Tr,
  139.                             &My_BA,&His_BA,
  140.                             &Best_Score_BA,Player,Bestest) ;
  141.  
  142.     (void)strcpy (Globerr,"Select_Best_2Dice_Move 3") ;
  143.  
  144.     if (Best_Score_AB.Moves_Made > Best_Score_BA.Moves_Made) {
  145.         Copy_AB = TRUE ;
  146.         Copy_BA = FALSE ;
  147.     } else if (Best_Score_BA.Moves_Made > Best_Score_AB.Moves_Made) {
  148.         Copy_BA = TRUE ;
  149.         Copy_AB = FALSE ;
  150.     } else if (Best_Score_BA.Moves_Made != 0) {
  151.         /* Moves_Made are equal and non zero in both cases, choose the best */
  152.         if (Best_Score_AB.Goodness > Best_Score_BA.Goodness) {
  153.             Copy_AB = TRUE ;
  154.             Copy_BA = FALSE ;
  155.         } else {
  156.             Copy_BA = TRUE ;
  157.             Copy_AB = FALSE ;
  158.         }
  159.     } else {
  160.         Copy_BA = FALSE ;
  161.         Copy_AB = FALSE ;
  162.     }
  163.  
  164.     (void)strcpy (Globerr,"Select_Best_2Dice_Move 4") ;
  165.  
  166.     if (Copy_AB) {
  167.         Copy_Transit (My_Best_Tr,&My_AB) ;
  168.         Copy_Transit (His_Best_Tr,&His_AB) ;
  169.     } else if (Copy_BA) {
  170.         Copy_Transit (My_Best_Tr,&My_BA) ;
  171.         Copy_Transit (His_Best_Tr,&His_BA) ;
  172.     }
  173.  
  174.     (void)strcpy (Globerr,"Select_Best_2Dice_Move 5") ;
  175. }
  176.  
  177. /*************************************************************************/
  178.  
  179. void Select_Best_Ndice_Move (Dice_t*    Dice_List,  short      This_Dice,
  180.                              Transit_t* My_Curr_Tr, Transit_t* His_Curr_Tr,
  181.                              Transit_t* My_Best_Tr, Transit_t* His_Best_Tr,
  182.                              Lay_Sel_t* Best_Score, Player_t   Player,
  183.                              Search_t   Search)
  184. /*
  185. PURPOSE: To select the best or most legal move so far.
  186. NOTES  : 1) If Depth_Only then we don't care about the goodness of the
  187.             move, only the legality of it. And we stop searching as soon
  188.             as we have found a legal move of 4, the maximum possible.
  189.          2) If This_Dice = -1 then we have stopped recursion, obviously
  190. */
  191. {
  192.     static short Moves_Done = 0 ;
  193.  
  194.     if (Won (My_Best_Tr->Layout,His_Best_Tr->Layout) > NO_WIN) {
  195.         return ;
  196.     }
  197.  
  198.     #if DEBUG_SOURCE
  199.     (void)strcpy (Globerr,"Select_Best_Ndice_Move 1") ;
  200.     Check_Layout (My_Curr_Tr->Layout,"Checking My_Curr_Tr") ;
  201.     Check_Layout (His_Curr_Tr->Layout,"Checking His_Curr_Tr") ;
  202.     if (This_Dice > 3) {
  203.         printf ("\nInvalid Dice value: %d",This_Dice) ;
  204.         Error_Exit ("Invalid Dice value") ;
  205.     }
  206.     #endif
  207.  
  208.     if (This_Dice >= 0) {
  209.         char p ;
  210.         boolean Something_Moved ;
  211.  
  212.         Something_Moved = FALSE ;
  213.         for (p = BAR_I ; p <= POINT24_I ; p++) {
  214.             if (Can_Move (p,Dice_List->Values[This_Dice],
  215.                           My_Curr_Tr->Layout,His_Curr_Tr->Layout)) {
  216.                 /* It is ok to move from 'p' with this dice value */
  217.                 Transit_t My_Temp,His_Temp ;
  218.  
  219.                 Something_Moved = TRUE ;
  220.                 Copy_Transit (&My_Temp,My_Curr_Tr) ;
  221.                 Copy_Transit (&His_Temp,His_Curr_Tr) ;
  222.  
  223.                 Execute_Move (p,Dice_List->Values[This_Dice],
  224.                               &My_Temp,&His_Temp) ;
  225.  
  226.                 Moves_Done++ ;
  227.                 if (Moves_Done > 4) {
  228.                     Error_Exit ("Moves_Done > 4") ;
  229.                 }
  230.                 (void)strcpy (Globerr,"Select_Best_Ndice_Move 2") ;
  231.  
  232.                 /* Recurse... */
  233.                 Select_Best_Ndice_Move (Dice_List, This_Dice-1,
  234.                                         &My_Temp,&His_Temp,
  235.                                         My_Best_Tr,His_Best_Tr,
  236.                                         Best_Score,Player,Search) ;
  237.                 Moves_Done-- ;
  238.             }
  239.         }
  240.         if (!Something_Moved) {
  241.             /* No more moves possible in this branch, end recursion
  242.             and choose a move. */
  243.             (void)strcpy (Globerr,"Select_Best_Ndice_Move 3") ;
  244.             Choose_Move (My_Curr_Tr, His_Curr_Tr,
  245.                          Player,Moves_Done,
  246.                          My_Best_Tr,His_Best_Tr,Best_Score,Search) ;
  247.         }
  248.         if (Moves_Done < 0) {
  249.             Error_Exit ("Moves < 0 ") ;
  250.         }
  251.     } else {
  252.         /* No more dice, see if this any better than previous best */
  253.         if ((Search == Legalest) && (Best_Score->Moves_Made == 4)) {
  254.             /* No more choosing to do, we already know the maximum number
  255.             of moves to do */
  256.             return ;
  257.         }
  258.         Choose_Move (My_Curr_Tr,His_Curr_Tr,
  259.                          Player,Moves_Done,
  260.                          My_Best_Tr,His_Best_Tr,Best_Score,Search) ;
  261.  
  262.     }
  263. }
  264.  
  265. /*************************************************************************/
  266.  
  267. void Choose_Move (Transit_t*  Mine,    Transit_t* His,
  268.                   Player_t    Player,  short      Moves_Done,
  269.                   Transit_t*  My_Best, Transit_t* His_Best,
  270.                   Lay_Sel_t*  Best_Score,         Search_t Search)
  271. /*
  272. PURPOSE: We have to choose between two moves, the previous best and
  273.          the one handed to us here.
  274. NOTES:   1) We change the best variables to this one if it is better.
  275.          2) The number of moves made takes precedence over the goodness
  276.             of the move. According to the rules of Backgammon you must
  277.             make the most moves possible.
  278.          3) Usually this is the function called at the end of a recursive
  279.             branch.
  280.          4) If the search type is just looking for max moves then we do
  281.             not evaluate the move, just look at the Moves_Done, to get
  282.             a legal move.
  283. */
  284. {
  285.     boolean Copy ;
  286.     long Goodness ;
  287.  
  288.     (void)strcpy (Globerr,"Choose_Move 1") ;
  289.  
  290.     if (Search == Bestest) {
  291.         Goodness = Evaluate_Move (Mine->Layout,His->Layout,Player) ;
  292.     } else if (Search == Legalest) {
  293.         Goodness = 0 ;
  294.     } else {
  295.         Error_Exit ("Bad Search value in Choose_Move") ;
  296.     }
  297.     if (Moves_Done < Best_Score->Moves_Made) {
  298.         Copy = FALSE ; /* The best move so far has moved more pieces than
  299.         this current move, so do not change the best move. */
  300.     } else {
  301.         if (Goodness > (Best_Score->Goodness)) {
  302.             /* An obviously better move */
  303.             Copy = TRUE ;
  304.         } else if (Goodness == (Best_Score->Goodness)) {
  305.             /* Choose at random between the two equal valued moves */
  306.             Copy = (Int_Rand_Range (0,100) > 50) ;
  307.         } else {
  308.             /* Not at all a good move */
  309.             Copy = FALSE ;
  310.         }
  311.     }
  312.     if (Copy) {
  313.         Copy_Transit (My_Best,Mine) ;
  314.         Copy_Transit (His_Best,His) ;
  315.         Best_Score->Goodness   = Goodness ;
  316.         Best_Score->Moves_Made = Moves_Done ;
  317.     }
  318. }
  319.  
  320. /*************************************************************************/
  321.  
  322. void Execute_Move (char p, char Die, Transit_t* Mine, Transit_t* His)
  323. /*
  324. PURPOSE: To move a piece from point p Die spaces forward. We will
  325.          eat one of his pieces if there is one. We record the new layouts
  326.          and move made in the transit types.
  327. */
  328. {
  329.     char New_Point,His_Point,Places_Moved ;
  330.  
  331.     New_Point = p + Die ;
  332.     if (New_Point > HOME_I) {
  333.         Places_Moved = Die - (New_Point - HOME_I) ;
  334.         New_Point    = HOME_I ;
  335.     } else {
  336.         Places_Moved = Die ;
  337.     }
  338.     His_Point = Reverse_Index(New_Point) ;
  339.  
  340.     #if DEBUG_SOURCE
  341.     if (Mine->Layout[p] < 1) {
  342.         Error_Exit ("Trying to move a piece from an empty point") ;
  343.     } else if ((His->Layout[His_Point] > 1) && (New_Point != HOME_I)){
  344.         Error_Exit ("Trying to move a piece to a blocked point") ;
  345.     }
  346.     #endif
  347.  
  348.     /* Move my piece in the layout */
  349.     Mine->Layout [p]-- ;
  350.     Mine->Layout [New_Point]++ ;
  351.  
  352.     /* Record how the transit was made */
  353.     Mine->Old_Points [Mine->N_Moves] = p ;
  354.     Mine->Places_Movd[Mine->N_Moves] = Places_Moved ;
  355.  
  356.     /* Remember that Row is number of pieces-1 */
  357.     Mine->Old_Row    [Mine->N_Moves] = Mine->Layout[p] ;
  358.     Mine->New_Row    [Mine->N_Moves] = Mine->Layout[New_Point]-1 ;
  359.     Mine->N_Moves++ ;
  360.  
  361.     /* Eat his piece ? ... */
  362.     if ((His_Point != BAR_I) && (His_Point != HOME_I)) {
  363.         if (His->Layout[His_Point] == 1) {
  364.  
  365.             /* Move the point eaten back to the bar */
  366.             His->Layout[His_Point] = 0 ;
  367.             His->Layout[BAR_I]++ ;
  368.  
  369.             /* Record how his piece moved back to the bar */
  370.             His->Old_Points [His->N_Moves] = His_Point ;
  371.             His->Places_Movd[His->N_Moves] = BAR_I - His_Point  ;
  372.             His->Old_Row    [His->N_Moves] = 0 ;
  373.             His->New_Row    [His->N_Moves] = His->Layout[BAR_I]-1 ;
  374.             His->N_Moves++ ;
  375.         } else {
  376.             His->N_Moves = 0 ;
  377.         }
  378.     } else {
  379.         His->N_Moves = 0 ;
  380.     }
  381. }
  382.  
  383. /*************************************************************************/
  384.  
  385. boolean Can_Move (char p, char Die, Layout_t Me, Layout_t Him)
  386. /*
  387. PURPOSE: To return TRUE if a move is possible.
  388. */
  389. {
  390.     short New_Point ;
  391.  
  392.     if (Me[p] == 0) {
  393.         /* I have no pieces on this point */
  394.         return (FALSE) ;
  395.     }
  396.  
  397.     New_Point = p+Die ;
  398.     if (New_Point > HOME_I) {
  399.         /* The new point would be home */
  400.         New_Point = HOME_I ;
  401.     }
  402.  
  403.     if ((Him[Reverse_Index(New_Point)] > 1) && (New_Point != HOME_I)) {
  404.         /* He is occupying where I would have gone */
  405.         return (FALSE) ;
  406.     }
  407.  
  408.     if (New_Point == HOME_I) {
  409.         /* I want to go home... */
  410.         if (!Bearing_Off(Me)) {
  411.             /* ...but I am not bearing off. */
  412.             return (FALSE) ;
  413.         } else if ((p+Die) == HOME_I) {
  414.             /* ...and can move exactly to home */
  415.             return (TRUE) ;
  416.         } else if (Pieces_Behind(Me,p)) {
  417.             /* ...but pieces behind me, so cannot take piece home. */
  418.             return (FALSE) ;
  419.         }
  420.     }
  421.  
  422.     if ((p != BAR_I) && (Me[BAR_I] != 0)) {
  423.         /* Trying to move a non bar piece while still on bar */
  424.         return (FALSE) ;
  425.     }
  426.  
  427.     return (TRUE) ;
  428. }
  429.  
  430. /*************************************************************************/
  431.  
  432. void Copy_Layout (Layout_t Dst, Layout_t Src)
  433. /*
  434. PURPOSE: To copy the Src to the Dst.
  435. */
  436. {
  437.     ushort p ;
  438.  
  439.     for (p = 0 ; p < N_PLACES ; p++) {
  440.         Dst[p] = Src[p] ;
  441.     }
  442. }
  443.  
  444. /*************************************************************************/
  445.  
  446. boolean Bearing_Off (Layout_t Lay)
  447. /*
  448. PURPOSE: To return TRUE if all the pieces on the layout are in the
  449.          final quadrant.
  450. */
  451. {
  452.     ushort p ;
  453.  
  454.     p = BAR_I ;
  455.     do {
  456.         if (Lay[p] != 0) {
  457.             return (FALSE) ;
  458.         }
  459.         p++ ;
  460.     } while (p < 19) ;
  461.  
  462.     return (TRUE) ;
  463. }
  464.  
  465. /*************************************************************************/
  466.  
  467. short Won (Layout_t Me, Layout_t Him)
  468. /*
  469. PURPOSE: To return 0,SIMPLE,GAMMON or BACKGAMMON according to the layout.
  470. */
  471. {
  472.     short p ;
  473.     if (Me[HOME_I] == N_PIECES) {
  474.         /* We have won, now work out by how much */
  475.         if (Him[HOME_I] > 0) {
  476.             /* He has taken off at least one piece */
  477.             return (SIMPLE) ;
  478.         } else {
  479.             /* It all depends on where is the last piece */
  480.             for (p = BAR_I ; p < HOME_I ; p++ ) {
  481.                 if (Him[p] > 0) {
  482.                     break ;
  483.                 }
  484.             }
  485.             if (p < 7) {
  486.                 /* He has a piece in my inner table */
  487.                 return (BACKGAMMON) ;
  488.             } else {
  489.                 return (GAMMON) ;
  490.             }
  491.         }
  492.     } else {
  493.         return (NO_WIN) ;
  494.     }
  495. }
  496.  
  497. /*************************************************************************/
  498.  
  499. boolean Pieces_Behind (Layout_t Me, short p)
  500. /*
  501. PURPOSE: To return TRUE if there are any of my pieces further behind than
  502.          p.
  503. */
  504. {
  505.     p-- ;
  506.     while (p >= 0) {
  507.         if (Me[p]) {
  508.             return (TRUE) ;
  509.         }
  510.         p-- ;
  511.     }
  512.     return (FALSE) ;
  513. }
  514.  
  515. /*************************************************************************/
  516.  
  517. void Check_Layout (Layout_t Layout, char* Err_Mess)
  518. /*
  519. PURPOSE: To check that the layout is legal, exiting with an
  520.          error message if it is not.
  521. */
  522. {
  523.     short Total,p ;
  524.     Total = 0 ;
  525.     for (p = BAR_I ; p < N_PLACES ; p++) {
  526.         Total = Total + Layout[p] ;
  527.     }
  528.     if (Total != N_PIECES) {
  529.         printf ("\nERROR: Total = %d",(int)Total) ;
  530.         printf ("\n ") ;
  531.         for (p = 0 ; p < N_PLACES ; p++) {
  532.             printf ("%3d",p) ;
  533.         }
  534.         printf ("\nM") ;
  535.         for (p = 0 ; p < N_PLACES ; p++) {
  536.             printf ("%3d",Layout[p]) ;
  537.         }
  538.         Error_Exit (Err_Mess) ;
  539.     }
  540. }
  541.  
  542. /*************************************************************************/
  543.  
  544. void Copy_Transit (Transit_t* Dest, Transit_t* Source)
  545. /*
  546. PURPOSE: To copy the source transit into the destination transit
  547. */
  548. {
  549.     short m ;
  550.  
  551.     #if DEBUG_SOURCE
  552.     if ((Source->N_Moves > 4) || (Source->N_Moves < 0)) {
  553.         printf ("\nCopy_Transit, N_Moves = %d",Source->N_Moves) ;
  554.         Error_Exit ("bad N_Moves in Copy_Transit") ;
  555.     }
  556.     #endif
  557.  
  558.     Copy_Layout (Dest->Layout,Source->Layout) ;
  559.     Dest->N_Moves = Source->N_Moves ;
  560.     for (m = 0 ; m < Dest->N_Moves ; m++) {
  561.  
  562.         #if DEBUG_SOURCE
  563.         if ((Source->Old_Points[m] + Source->Places_Movd[m]) > HOME_I) {
  564.             printf ("\nERROR Points[%d]=%d Source->Places_Movd[%d]",
  565.                      m,Source->Old_Points[m] + Source->Places_Movd[m],m) ;
  566.             Error_Exit ("in Copy_Transit Old+Places_Moved > HOME_I") ;
  567.         }
  568.         #endif
  569.  
  570.         Dest->Old_Points  [m] = Source->Old_Points  [m] ;
  571.         Dest->Places_Movd [m] = Source->Places_Movd [m] ;
  572.         Dest->Old_Row     [m] = Source->Old_Row     [m] ;
  573.         Dest->New_Row     [m] = Source->New_Row     [m] ;
  574.     }
  575. }
  576.  
  577. /*************************************************************************/
  578.  
  579. void Init_Transit (Transit_t* New, Layout_t Old)
  580. /*
  581. PURPOSE: To copy the Old layout into the transit and init everything
  582.          else to zero.
  583. */
  584. {
  585.     Copy_Layout (New->Layout,Old) ;
  586.     New->N_Moves = 0 ;
  587. }
  588.  
  589. /*************************************************************************/
  590.  
  591. boolean Move_Possible (Layout_t P_Lay, Layout_t O_Lay)
  592. /*
  593. Returns TRUE if the the Players layout is not completly blocked by
  594. the Opponents layout.
  595. */
  596. {
  597.  
  598.     if (P_Lay [BAR_I] == 0) {
  599.         return (TRUE) ;
  600.     } else {
  601.         /* The player has a piece on the bar, has the opponent blocked
  602.         all six entry points? */
  603.         short p ;
  604.         for (p = 19 ; p <= POINT24_I ; p++) {
  605.             if (O_Lay[p] < 2) {
  606.                 return (TRUE) ; /* ...no, we can get out here */
  607.             }
  608.         }
  609.         return (FALSE) ; /* .. yes, all six blocked */
  610.     }
  611. }
  612.  
  613. /*************************************************************************/
  614.  
  615.